package com.zzyl.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.bean.copier.CopyOptions;
import cn.hutool.core.collection.ListUtil;
import cn.hutool.json.JSONUtil;
import com.aliyun.iot20180120.Client;
import com.aliyun.iot20180120.models.*;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.zzyl.base.PageResponse;
import com.zzyl.constant.CacheConstants;
import com.zzyl.dto.DeviceDto;
import com.zzyl.dto.DevicePageQueryDto;
import com.zzyl.entity.Device;
import com.zzyl.enums.BasicEnum;
import com.zzyl.enums.DeviceLocationTypeEnum;
import com.zzyl.enums.DevicePhysicalLocationTypeEnum;
import com.zzyl.exception.BaseException;
import com.zzyl.mapper.DeviceMapper;
import com.zzyl.properties.AliIoTConfigProperties;
import com.zzyl.service.DeviceService;
import com.zzyl.utils.ObjectUtil;
import com.zzyl.vo.DeviceVo;
import com.zzyl.vo.ProductVo;
import lombok.Data;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import java.util.Collections;
import java.util.List;

@Slf4j
@Service
@RequiredArgsConstructor
public class DeviceServiceImpl implements DeviceService {

    private final AliIoTConfigProperties aliIoTConfigProperties;

    private final Client client;

    private final StringRedisTemplate redisTemplate;

    private final DeviceMapper deviceMapper;

    /**
     * 同步产品列表
     */
    @Override
    public void syncProductList() {
        //请求同步产品数据,SDK
        QueryProductListRequest request = new QueryProductListRequest();
        //参数设置
        request.setCurrentPage(1);
        request.setPageSize(200);
        request.setIotInstanceId(aliIoTConfigProperties.getIotInstanceId());
        //发送请求
        try {
            QueryProductListResponse response = client.queryProductList(request);
            if (response.getBody().getSuccess()){
                List<ProductVo> productVos = BeanUtil.copyToList(response.getBody().getData().getList().getProductInfo(), ProductVo.class);
                //存入redis
                redisTemplate.opsForValue().set(CacheConstants.ALL_PRODUCT_KEY, JSONUtil.toJsonStr(productVos));
                return;
            }
        } catch (Exception e) {
            log.info("产品调用失败:",e);
        }
        throw new BaseException(BasicEnum.IOT_LIST_PRODUCT_ERROR);
    }

    /**
     * 获取产品列表
     * @return
     */
    @Override
    public List<ProductVo> getProductList() {
        //从redis里面取
        String jsonStr = redisTemplate.opsForValue().get(CacheConstants.ALL_PRODUCT_KEY );
        if (ObjectUtil.isEmpty(jsonStr)) {
            //如果为空就返回空集合
            return Collections.emptyList();
        }
        return JSONUtil.toList(jsonStr, ProductVo.class);
    }

    /**
     * 注册设备
     * @param deviceDto
     */
    @Override
    public void registerDevice(DeviceDto deviceDto) {
        //1.检查设备名称是否重复
        Integer count = deviceMapper.countByDeviceName(deviceDto.getDeviceName());
        if (count > 0){
            throw new BaseException(BasicEnum.DEVICE_NAME_EXIST);
        }
        //2.注册设备
        //先获取IOTId,前端没传,需要自己从阿里拉取
        String iotId = getIotId(deviceDto);
        deviceDto.setIotId(iotId);
        //3.获取产品名名称
        String productName = getProductName(deviceDto.getProductKey());
        deviceDto.setProductName(productName);
        //4.如果是随身设备,把物理位置置为-1
        if (DeviceLocationTypeEnum.PORTABLE_DEVICE.getOrdinal().equals(deviceDto.getLocationType())){
            deviceDto.setPhysicalLocationType(DevicePhysicalLocationTypeEnum.ELDER.getOrdinal());
        }
        //5.保存到数据库
        Device device = BeanUtil.copyProperties(deviceDto, Device.class);
        device.setHaveEntranceGuard(0);
        Integer result = deviceMapper.insert(device);
        if (result == 0){
            //构建删除实例
            DeleteDeviceRequest request = new DeleteDeviceRequest();
            request.setIotId(iotId);
            request.setProductKey(deviceDto.getProductKey());
            request.setDeviceName(deviceDto.getDeviceName());
            request.setIotInstanceId(aliIoTConfigProperties.getIotInstanceId());
            deleteDevice(request);
            throw new BaseException(BasicEnum.DEVICE_REGISTER_ERROR);
        }
    }

    /**
     * 分页查询设备
     * @param devicePageQueryDto
     * @return
     */
    @Override
    public PageResponse<DeviceVo> pageQueryDevice(DevicePageQueryDto devicePageQueryDto) {
        //分页
        PageHelper.startPage(devicePageQueryDto.getPageNum(), devicePageQueryDto.getPageSize());
        //查询
        Page<DeviceVo> deviceVos = deviceMapper.pageQueryDevice(devicePageQueryDto);
        //转换
        return PageResponse.of(deviceVos,DeviceVo.class);
    }

    /**
     * 查询设备详细数据
     * @param request
     * @return
     */
    @Override
    public DeviceVo queryDeviceDetail(QueryDeviceDetailRequest request) {
        //从数据库查
        DeviceVo deviceVo = deviceMapper.queryDeviceDetail(request.getIotId());
        //从物联网查
        request.setIotInstanceId(aliIoTConfigProperties.getIotInstanceId());
        try {
            QueryDeviceDetailResponse response = client.queryDeviceDetail(request);
            if (response.getBody().getSuccess()){
                //注意忽略null值
                BeanUtil.copyProperties(response.getBody().getData(),deviceVo,CopyOptions.create().ignoreNullValue());
            }
        } catch (Exception e) {
            throw new BaseException(BasicEnum.IOT_QUERY_DEVICE_ERROR);
        }

        return deviceVo;
    }

    /**
     * 查询设备运行状态
     * @param request
     * @return
     */
    @Override
    public QueryDevicePropertyStatusResponseBody.
           QueryDevicePropertyStatusResponseBodyData
           QueryDevicePropertyStatus(QueryDevicePropertyStatusRequest request) {
        //实例ID
        request.setIotInstanceId(aliIoTConfigProperties.getIotInstanceId());
        //定义返回实例
        QueryDevicePropertyStatusResponseBody.
        QueryDevicePropertyStatusResponseBodyData
                data = new QueryDevicePropertyStatusResponseBody.
                QueryDevicePropertyStatusResponseBodyData();
        //物联网查询状态
        try {
            QueryDevicePropertyStatusResponse response = client.queryDevicePropertyStatus(request);
            if (response.getBody().getSuccess()){
                data = response.getBody().getData();
            }
        } catch (Exception e) {
            throw new BaseException(BasicEnum.IOT_QUERY_DEVICE_ERROR);
        }
        return data;
    }

    /**
     * 查看指定产品的已发布物模型中的功能定义详情
     * @param request
     * @return
     */
    @Override
    public QueryThingModelPublishedResponseBody.
           QueryThingModelPublishedResponseBodyData
           QueryThingModelPublished(QueryThingModelPublishedRequest request) {
        //实例ID
        request.setIotInstanceId(aliIoTConfigProperties.getIotInstanceId());
        //定义返回实例
        QueryThingModelPublishedResponseBody.
        QueryThingModelPublishedResponseBodyData
                data = new QueryThingModelPublishedResponseBody.
                QueryThingModelPublishedResponseBodyData();
        //物联网查询
        try {
            QueryThingModelPublishedResponse response = client.queryThingModelPublished(request);
            if (response.getBody().getSuccess()){
                data = response.getBody().getData();
            }
        } catch (Exception e) {
            throw new BaseException(BasicEnum.IOT_QUERY_DEVICE_ERROR);
        }
        return data;
    }

    /**
     * 修改设备备注名称
     * @param deviceDto
     */
    @Override
    public void updateDevice(DeviceDto deviceDto) {
        //检查数据库是否有该设备
        Device device = deviceMapper.selectDeviceById(deviceDto.getId());
        if (device == null){
            throw new BaseException(BasicEnum.DEVICE_NOT_EXIST);
        }
        //请求更新实例,阿里提供批量更新的API
        BatchUpdateDeviceNicknameRequest request = new BatchUpdateDeviceNicknameRequest();
        //实例ID
        request.setIotInstanceId(aliIoTConfigProperties.getIotInstanceId());
        BatchUpdateDeviceNicknameRequest.BatchUpdateDeviceNicknameRequestDeviceNicknameInfo
        nicknameInfo= BeanUtil.toBean(deviceDto,BatchUpdateDeviceNicknameRequest.BatchUpdateDeviceNicknameRequestDeviceNicknameInfo.class);
        request.setDeviceNicknameInfo(ListUtil.toList(nicknameInfo));
        //调用物联网更新
        try {
            BatchUpdateDeviceNicknameResponse response = client.batchUpdateDeviceNickname(request);
            if (!response.getBody().getSuccess()){
                throw new BaseException(BasicEnum.IOT_BATCH_UPDATE_DEVICE_ERROR);
            }
        } catch (Exception e) {
            log.error("修改设备备注名称失败",e);
            throw new BaseException(BasicEnum.IOT_BATCH_UPDATE_DEVICE_ERROR);
        }

        // 保存位置
        device = BeanUtil.toBean(deviceDto, Device.class);
        //如果是随身设备，物理位置设为-1
        if (device.getLocationType().equals(DeviceLocationTypeEnum.PORTABLE_DEVICE.getOrdinal())) {
            device.setPhysicalLocationType(DevicePhysicalLocationTypeEnum.ELDER.getOrdinal());
        }
        //更新数据库
        deviceMapper.updateDevice(device);
    }

    /**
     * 删除设备
     * @param request
     */
    @Override
    public void deleteDevice(DeleteDeviceRequest request) {
        //构建产品参数
        Device device = deviceMapper.selectDeviceByIotId(request.getIotId());
        request.setProductKey(device.getProductKey());
        request.setDeviceName(device.getDeviceName());
        request.setIotInstanceId(aliIoTConfigProperties.getIotInstanceId());
        request.setIotId(device.getIotId());
        try {
            DeleteDeviceResponse response = client.deleteDevice(request);
            if (!response.getBody().getSuccess()){
                throw new BaseException(BasicEnum.IOT_DELETE_DEVICE_ERROR);
            }
        } catch (Exception e) {
            throw new BaseException(BasicEnum.IOT_DELETE_DEVICE_ERROR);
        }
    }

    /**
     * 获取产品名称
     * @param productKey
     * @return
     */
    private String getProductName(String productKey) {
        //构建查询产品请求对象
        QueryProductRequest queryProductRequest = new QueryProductRequest();
        queryProductRequest.setIotInstanceId(aliIoTConfigProperties.getIotInstanceId());
        queryProductRequest.setProductKey(productKey);
        QueryProductResponse queryProductResponse;
        try {
            queryProductResponse = client.queryProduct(queryProductRequest);
            //判断是否调用成功
            if (queryProductResponse.getBody().getSuccess()){
                //返回产品名称
                return queryProductResponse.getBody().getData().getProductName();
            }
        } catch (Exception e) {
            log.info("查询产品失败:",e);
        }
        throw new BaseException(BasicEnum.IOT_QUERY_DEVICE_ERROR);
    }

    /**
     * 获取IOTId
     * @param deviceDto
     * @return
     */
    private String getIotId(DeviceDto deviceDto) {
        //获取注册请求对象
        RegisterDeviceRequest request = deviceDto.getRegisterDeviceRequest();
        //设置实例ID
        request.setIotInstanceId(aliIoTConfigProperties.getIotInstanceId());
        //注册设备
        try {
            RegisterDeviceResponse response = client.registerDevice(request);
            if (response.getBody().getSuccess()){
                return response.getBody().getData().getIotId();
            }
        } catch (Exception e) {
            log.info("注册设备失败:",e);
        }
        throw new BaseException(BasicEnum.IOT_REGISTER_DEVICE_ERROR);
    }
}
